#pragma warning (disable:4786)

#include "stdafx.h"
#include "Options.h"
#include <sstream>
#include <stdio.h>
#include <string>
#include <sstream>

using namespace std;

//-------------------------------------

bool Options::load(const string & path)
{
	char _buff[128];
	char *str;
	string optname;
	int _nbOptionsLoaded = 0;
	string _key = OPTIONS_SECTION_KEY;
	
	FILE *f = fopen(path.c_str(),"r");
	
	if (f == NULL)
	{
		return false;
	}
	else
	{
		while(fgets(&_buff[0], 128, f) != NULL)
		{				
			//////
			// Case of header
			//////
			if (_buff[0] == SECTION_HEADER_FIRST_CHAR)
			{
				_key = strtok(&_buff[1], SECTION_HEADER_LAST_CHAR_STR);
			}
			//////
			// default case = options list
			//////
			else
			{
				// Get opt name
				if ((str = strtok(_buff, "=")) != NULL)
				{
					optname = str;

					// Get opt value
					if ((str = strtok(NULL, "\n")) != NULL)
					{
						// Add option to map
						setOption(optname, str, _key);
						_nbOptionsLoaded++;
					}
				}
			}
		}
		fclose(f);
		return (_nbOptionsLoaded > 0);
	}
}
//-------------------------------------

bool Options::save(string path) const
{
	FILE *f = fopen(path.c_str(), "w+");

	if (f == NULL)
	{
		AfxMessageBox(_T("Failed to save options"));
		return false;
	}
	else
	{
		const_iterator _it;
		OptionsAssoc::iterator _itopts;
		// For each section
		for (_it = begin(); _it != end(); _it++)
		{
			// Print section name
			fprintf(f, "%c%s%c\n", SECTION_HEADER_FIRST_CHAR, _it->first.c_str(), SECTION_HEADER_LAST_CHAR);
			// Then, for each option
			for (_itopts = _it->second->begin(); _itopts != _it->second->end(); _itopts++)
			{
				// Dump the option's key and value
				if (_itopts->first.length() > 0 && _itopts->second.length() > 0)
					fprintf(f, "%s=%s\n", _itopts->first.c_str(), _itopts->second.c_str());
			}
			fprintf(f, "\n");
		}
		fclose(f);
		return true;
	}
}
//--------------------------------

bool Options::getOptions(const string & sectionName, OptionsAssoc **p_options, bool createIfNotExists)
{
	bool _rc = true;

	Options::iterator _it = this->find(sectionName);

	if (_it != this->end())
	{
		*p_options = _it->second;
	}
	else if (createIfNotExists)
	{
		*p_options = new OptionsAssoc();
		(*this)[sectionName] = *p_options;
	}
	else
	{
		_rc = false;
	}
	return _rc;
}
//--------------------------------

bool Options::getOptionNamesForSection(const string & sectionName, vector<string> & _optionsList)
{
	OptionsAssoc *_options;
	if (getOptions(sectionName, &_options, true))
	{
		OptionsAssoc::iterator _it;
		for (_it = _options->begin(); _it != _options->end(); _it++)
		{
			_optionsList.push_back(_it->first);
		}
		return true;
	}
	return false;
}

void Options::setOption(const string & optionName, const string & optionValue, const string & sectionName)
{
	OptionsAssoc *_options;
	if (getOptions(sectionName, &_options, true))
	{
		(*_options)[optionName] = optionValue;
	}
}
//--------------------------------

bool Options::getOption(const string & optionName, string & optionValue, const string & sectionName)
{
	OptionsAssoc *_options = NULL;
	if (getOptions(sectionName, &_options))
	{
		OptionsAssoc::const_iterator it = _options->find(optionName);
		if (it != _options->end()) {
			optionValue = it->second;
			return true;
		}
	}
	return false;
}
//--------------------------------

bool Options::getOption(const string & optionName, CString &optionValue, const string & sectionName)
{
	string s;
	bool found = getOption(optionName, s, sectionName);

	if (found)
	{
		optionValue = s.c_str();
		return true;
	}
	return false;
}
//--------------------------------
void Options::setIntOption(const std::string & optionName, int optionValue, const string & sectionName)
{
	stringstream s;
	s << optionValue;
	setOption(optionName, s.str(), sectionName);
}
//--------------------------------

bool Options::getIntOption(const std::string & optionName, int & optionValue, const string & sectionName)
{
	string strValue;

	if (getOption(optionName, strValue, sectionName))
	{
		optionValue = strtol(strValue.c_str(), NULL, 10);
		return true;
	}
	else
	{
		return false;
	}
}
//--------------------------------

void Options::delOption(const string & optionName,
			   const string & sectionName)
{
	Options::iterator _itSection = this->find(sectionName);
	if (_itSection != this->end())
	{
		OptionsAssoc *_options = _itSection->second;
		OptionsAssoc::iterator it = _options->find(optionName);
		if (it != _options->end()) 
		{
			_options->erase(it);
			if (_options->size() == 0)
			{
				this->erase(_itSection);
			}
		}
	}
}